/*
 * Created on Aug 19, 2008
 */
package com.mgmaps.utils;

import com.mgmaps.app.APPCanvas;
import com.nutiteq.components.WgsPoint;
import com.nutiteq.listeners.MapListener;

public class DelayedMapListener extends Thread implements MapListener {
  
  // TODO update this definition with customizable delays
  private static final int DEFAULT_DELAY = 2000;
  private static final int DEFAULT_TIMEOUT_INTERVAL = 60000;
  private int mapDelay;
  private MapListener listener;

  private boolean stopping;
  private boolean now;
  
  private long lastCall;
  private int timeoutInterval;
  
  public DelayedMapListener(MapListener listener) {
    this(listener, DEFAULT_DELAY, DEFAULT_TIMEOUT_INTERVAL);
  }
  
  public DelayedMapListener(MapListener listener, int mapDelay, int timeoutInterval) {
    this.mapDelay = mapDelay;
    this.timeoutInterval = timeoutInterval-mapDelay;
    this.listener = listener;
    start();
  }

  public void mapClicked(WgsPoint point) {
    listener.mapClicked(point);
  }

  public void mapMoved() {
    update(false);
  }

  public void needRepaint(boolean mapIsComplete) {
    listener.needRepaint(mapIsComplete);
  }

  /**
   * Main thread method.
   * 
   * @see java.lang.Thread#run()
   */
  public void run() {
    while (!stopping) {
      try {
        synchronized(this) {
          wait(timeoutInterval);
        }
      }
      catch (InterruptedException inte) {
      }
      
      // break the loop if stopping 
      if (stopping)
        break;
        
      try {
        // sleep for a while if needed
        long newMillis = 0;
        boolean flag2;
        if (!now) {
          final long oldMillis = System.currentTimeMillis();
          synchronized(this) {
            wait(mapDelay);
          }

          // notified before delay? continue the loop without updating the map
          // but first check if the timeout interval has passed
          newMillis = System.currentTimeMillis();
          boolean flag1 = (newMillis - oldMillis) < mapDelay;
          flag2 = (newMillis - lastCall) < timeoutInterval; 
          if (flag1 && flag2)
            continue;
        }
        else {
          newMillis = System.currentTimeMillis();
          flag2 = (newMillis - lastCall) < timeoutInterval;
        }
          
        // run the update
        if (listener instanceof APPCanvas)
          ((APPCanvas) listener).mapMoved(!flag2);
        else
          listener.mapMoved();
        lastCall = newMillis;
        now = false;
      }
      catch (InterruptedException inte2) {
        // ignore and continue the loop
      }
    }
  }
  
  /**
   * Update this service.
   * 
   * @param setNow new value for now
   */
  public synchronized void update(boolean setNow) {
    now = setNow;
    if (lastCall == 0)
      lastCall = System.currentTimeMillis();
    notify();
  }
  
  public synchronized void setTimeoutInterval(int timeoutInterval) {
    this.timeoutInterval = timeoutInterval-mapDelay;
  }
  
  /**
   * Set the quitting flag.
   */
  public synchronized void setQuitting() {
    stopping = true;
    notify();
  }
}
